Javascript 성능 향상 코딩 팁
자바스크립트 성능 측정 방법
- console.time
console.time(0);
// 여러가지 로직 수행
console.timeEnd(0);
console.time('t1');
// 다양한 로직 수행
console.timeEnd('t1');
0: 7468.280029296875 ms
- performance.now
var t1 = performance.now();
// 여러가지 로직 수행
var t2 = performance.now();
console.log("소요 시간: " + (t2 - t1) + 'ms')
소요 시간: 5976.399999976158ms
console.time 이 더 사용하기 쉬우나 비표준이므로 디버깅 용도로만 사용할 것. 프로덕션 환경에서는 사용하지 않는 것이 좋다.
performance.now 는 사용하기는 번거롭지만 표준이며, one thousandth of a millisecond 의 정확도를 가지고 있어 정밀한 측정이 가능하다.
성능 향상을 위한 코딩
변수 선언을 한번에 하는 방법
// 한번에 여러개의 변수를 할당할 수 있다.
const a = 1,
b = 2,
c = 3;
Loop 성능 향상 방법
const person = {
home : [
{ addr:'서울', country : 'ko'},
{ addr:'대전', country : 'ko'},
{ addr:'대구', country : 'ko'},
{ addr:'부산', country : 'ko'},
{ addr:'파리', country : 'fr'}
]
}
for (let i=0; i < person.home.length; i++){
console.log(person.home[i]);
}
// 위 코드는 아래와 같은 단계를 거침
// 1) i값 탐색
// 2) person 객체 탐색
// 3) home 속성 탐색
// 4) home 속성의 인덱스 탐색
// 5) length 프로퍼티 검색
// for 문을 수행하는 동안 위 5단계를 계속 반복
// => 아래와 같이 향상
let len = person.home.length; // length 1회 접근
for (let i=0; i < len; i++){
console.log(person.home[i]);
}
// => 아래와 같이 향상
for (let i=0, len=person.home.length; i < len; i++){ // 전역으로 선언하지 않아 메모리 절감
console.log(person.home[i]);
}
// => 아래와 같이 향상
let list = person.home; // list에 person 객체의 home 속성을 미리 할당.
for (let i=0, len = list.length; i < len ; i++){
console.log(list[i]); // 반복할 때 마다 person 객체의 home 속성에 접근할 필요 없음.
}
// => chatGPT 솔루션
person.home.forEach(item => {
console.log(item);
});
정규표현식 Loop 성능 향상
for (let i = 0; i < 100; i++) {
str[i].replace(/^\d{3}-\d{3,4}-\d{4}$/, "");
}
// 정규 표현식은 컴파일 이후 처리가 필요. 100회의 반복적인 컴파일을 수행하게 된다.
// => 아래와 같이 향상
let reg = /^\d{3}-\d{3,4}-\d{4}$/; // 1회만 컴파일
for (let i = 0; i < 100; i++) {
str[i].replace(reg, "");
}
조건 비교 연산 성능 향상
let value = 3;
if (value === 1) {
...
} else if (value === 2) {
...
} else if (value === 3) { // 맨 위부터 순차적으로 비교
...
}
// => 아래와 같이 향상
switch (value) {
case 1 :
...
case 2 :
...
case 3 : // 3으로 바로 진입
...
}
스크립트 선언을 통한 성능 향상
// 브라우저의 렌더링 엔진은 HTML문서를 한줄 한줄 순차적으로 파싱하며 DOM을 생성
<html>
<head>
<meta charset="UTF-8"> // 여기까지 파싱했고...
<link rel="stylesheet" href="style.css"/>
<style type="text/css">
...
// link 태그를 만나면 CSS파일을 서버에 요청한 후 응답받아 CSS파싱을 시작.
// style 태그는 상단에 선언하여 DOM 렌더링이 다시 이루어지지 않도록 하는 것이 좋다.
</style>
</head>
<body>
...
<script type="text/javascript"> // 가급적 최하단에 script 선언
...
// script 태그를 만나면 DOM 파싱을 중단하고 script 엔진에 제어권을 넘긴다.
// DOM이 완성되지 않은 상태에서 DOM Api를 통해 DOM을 조작하면 에러가 발생할 수 있음.
// 자바스크립트의 로딩/파싱/실행으로 인해 페이지의 로딩 시간이 길어질 수 있다.
// 스크립트 처리가 지연되는 경우 사용자는 빈 화면 또는 미완성된 화면을 볼 수 있다.
</script>
</body>
</html>
정리하면 아래와 같다.
브라우저 렌더링은 HTML 파서, CSS 파서, Javascript 엔진이 처리한다.
- HTML파서가 한줄 한줄 파싱
- link 또는 style 태그를 만나면 CSS파서가 파싱
- 1, 2 는 병렬적으로 처리된다.
- 1, 2 는 머지 되어 Painting 이 이루어 진다.
- 스크립트가 실행되는 동안 문서의 파싱은 중단된다. 스크립트가 외부에 있는 경우 우선 네트워크로부터 자원을 가져와야 하는데 이 또한 실시간으로 처리되고 자원을 받을 때까지 파싱은 중단된다.
결론적으로 사용자에게 빠르게 화면을 보여주기 위해서 파싱 중단을 야기하는 Script 태그는 하단에 배치하는것이 바람직하다.
Reflow 를 최소화
DOM의 변경으로 다시 렌더 트리를 재생성 하는 과정을 Reflow, 재생성된 렌더 트리를 다시 그리는걸 Repaint(or Redraw) 라고 한다.
var target = document.getElementById('container');
for (var i = 0 ; i < 1000; i++){
var div = document.createElement('div');
div.innerText = i;
target.appendChild(div); // 1000번의 reflow 발생
}
// => 아래와 같이 향상
var fragment = document.createDocumentFragment();
for (var i = 0 ; i < 1000; i++){
var div = document.createElement('div');
div.innerText = i;
flagment.appendChild(div);
}
var target = document.getElementById('container');
target.appendChild(flagment); // 1번의 reflow 발생